package com.gzy.studentsociety.web;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import static com.sun.corba.se.impl.activation.ServerMain.logError;

public abstract class RouteServlet extends HttpServlet {

    private String getRoute(String url) {
        url = url.replaceAll("/studentSociety", "");
        String[] levels = url.split("[?]")[0].split("/");
        return levels[levels.length - 1];
    }

    protected abstract Class getMyClass();

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("application/json;charset=UTF-8");

        String url = req.getRequestURI();
        String methodName = getRoute(url);
        Object obj = null;
        try {
            Method method = getMyClass().getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
            obj = method.invoke(this, req, resp);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
            handleException(e, req, resp);
        }
        forward(obj, req, resp);
    }

    private String getJson(Object obj) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 允许空属性
        return objectMapper.writeValueAsString(obj);
    }

    private void forward(Object obj, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        if (obj != null) {
            if (obj instanceof String) {
                // 这里是正常的 JSP 页面转发
                if (!"direct".equals((String) obj)) {
                    if (!resp.isCommitted()) { // 仅当响应未提交时才进行转发
                        req.getRequestDispatcher("/WEB-INF/jsp/" + (String) obj + ".jsp").forward(req, resp);
                    }
                }
            } else {
                // 处理 JSON 输出
                String json = getJson(obj);
                if (!resp.isCommitted()) {  // 仅当响应未提交时才输出 JSON
                    PrintWriter out = resp.getWriter();
                    out.write(json);
                    out.flush();
                }
            }
        } else {
            // 如果 obj 为 null，转发到 error 页面，但仅在响应未提交时
            if (!resp.isCommitted()) {
                req.getRequestDispatcher("/WEB-INF/jsp/error.jsp").forward(req, resp);
            }
        }
    }

    protected void handleException(Throwable e, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setAttribute("exception", e);

        // 检查响应是否已经提交
        if (!resp.isCommitted()) {
            // 如果没有提交响应，继续转发到错误页面
            req.getRequestDispatcher("/WEB-INF/jsp/error.jsp").forward(req, resp);
        } else {
            // 如果响应已提交，只记录错误或采取其他措施
            logError("Response already committed, cannot send error.", e);

            // 可以选择直接返回 500 错误代码（这时候不能再调用 sendError()）
            resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

    private void logError(String s, Throwable e) {
    }

}
